package org.box.metadata.shell.web;

import java.io.PrintStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.collections.buffer.BoundedFifoBuffer;
import org.box.metadata.cli.MetaCli;
import org.box.metadata.cli.MetaCommandLineParser.ParserType;
import org.box.metadata.cli.exception.ParseException;
import org.box.metadata.shell.AbstractShell;
import org.box.metadata.shell.WebConsoleDefaultConfiguration;
import org.box.metadata.shell.WebConsoleModule;
import org.box.metadata.shell.WebConsoleModule.ServerOutStream;
import org.box.metadata.shell.console.ConsoleDefaultConfiguration;
import org.eclipse.jetty.server.Server;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class WebShell extends AbstractShell {
	
	private static final Logger LOG = Logger.getLogger(WebShell.class.getName());
	private final BoundedFifoBuffer inBuffer = new BoundedFifoBuffer(100);
	
	private volatile boolean consoleBusy = true;
	private volatile String currentInput;
	private volatile String currentSession;
	
	public WebShell(Class<?> cfgClass) {
		super(cfgClass, ConsoleDefaultConfiguration.class, WebConsoleDefaultConfiguration.class);
	}

	public WebShell(ParserType parserType, Class<?> cfgClass) {
		super(parserType, cfgClass, ConsoleDefaultConfiguration.class, WebConsoleDefaultConfiguration.class);
	}

	/*
	 * (non-Javadoc)
	 * @see org.box.metadata.shell.Shell#displayMessage(java.lang.String)
	 */
	@Override
	public void displayMessage(String msg) {
		System.out.println(msg);
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.box.metadata.shell.AbstractShell#run(java.lang.String[])
	 */
	@Override
	public void run(String[] args) {
		
		WebConsoleDefaultConfiguration cfg = new WebConsoleDefaultConfiguration();
		try {
			cfg = MetaCli.parse(args, WebConsoleDefaultConfiguration.class);
		} catch (ParseException e) {
			if (LOG.isLoggable(Level.WARNING))
				LOG.warning("Unable to create custom configuration: " + e.getMessage());
		}
		
		Injector injector = Guice.createInjector(new WebConsoleModule(cfg));

		Server server = injector.getInstance(NativeServer.class);
		try {
			server.start();
		} catch (Exception e) {
			throw new RuntimeException("Unable to start Native Server: ", e);
		}
		
		PrintStream origOut = System.out;
		System.setOut(new PrintStream(injector.getInstance(ServerOutStream.class)));

		super.run(new String[0]);
		
		System.setOut(origOut);
		
		try {
			server.stop();
		} catch (Exception e) {
			throw new RuntimeException("Unable to stop Jetty Server: ", e);
		}
	}


	/*
	 * (non-Javadoc)
	 * @see org.box.metadata.shell.AbstractShell#getUserInput()
	 */
	@Override
	protected String getUserInput() {
		while (inBuffer.isEmpty()) {
			synchronized (this) {
				try {
					consoleBusy = false;
					currentInput = null;
					currentSession = null;
					wait();
				} catch (InterruptedException e) {
					System.err.println("Warning: " + e);
				}
			}
		} 
		consoleBusy = true;
		
		synchronized (inBuffer) {
			String[] remove = (String[]) inBuffer.remove();
			currentInput = remove[0];
			currentSession = remove[1];
			return currentInput;
		}
	}
	
	public boolean isConsoleBusy() {
		return consoleBusy;
	}
	
	public void	submitInput(String input, String sessionId) {
		synchronized (inBuffer) {
			if (!inBuffer.isFull()) {
				inBuffer.add(new String[]{input, sessionId});
			}
		}
		
		synchronized (this) {
			notify();
		}
	}
	
	public String getCurrentInput() {
		return currentInput;
	}
	
	public String getCurrentSession() {
		return currentSession;
	}
}
